﻿using System;
using System.Collections.Generic;
using netDxf;
using netDxf.Entities;
using netDxf.Tables;

namespace TestDxfDocument
{
    public class commonfun
    {

        /// <summary>
        /// 点p1,p2所在的直线与circle圆的交点 有两个交点版本 不允许是竖直线
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="circle"></param>
        /// <returns></returns>
        public static List<Vector2> getPointOFLineandCircle(Vector2 p1, Vector2 p2, Circle circle)
        {
            Vector2 firstPoint = new Vector2(0, 0);
            Vector2 secondPoint = new Vector2(0, 0);
            
            Vector2 circleCenter = fun.toTwo(circle.Center);
            double rad = circle.Radius;

            double[] kb = binaryEquationGetKB(p1, p2);
            double k = kb[0];
            double b = kb[1];

            double aX = 1 + k * k;
            double bX = 2 * k * (b - circleCenter.Y) - 2 * circleCenter.X;
            double cX = circleCenter.X * circleCenter.X + (b - circleCenter.Y) * (b - circleCenter.Y) - rad * rad;

            List<double> xArr = quadEquationGetX(aX, bX, cX);
            List<Vector2> res = new List<Vector2>();
            foreach (var x in xArr)
            {
                double y = k * x + b;
                res.Add(new Vector2(x, y));
            }
            
            
            return res;
        }
        
        /// <summary>
        /// 求二元一次方程的系数
        /// y1 = k * x1 + b => k = (y1 - b) / x1
        /// y2 = k * x2 + b => y2 = ((y1 - b) / x1) * x2 + b
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        public static double[] binaryEquationGetKB(Vector2 p1, Vector2 p2)
        {
            double k = (p1.Y - p2.Y) / (p1.X - p2.X);
            double b = (p1.X * p2.Y - p2.X * p1.Y) / (p1.X - p2.X);
            return new[] {k, b};
        }
        
        /// <summary>
        /// 一元二次方程求根
        /// ax² + bx + c = 0
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        public static List<double> quadEquationGetX(double a,double b,double c)
        {
            List<double> xArr = new List<double>();
            double result = Math.Pow(b, 2) - 4 * a * c;
            if (result > 0)
            {
                double value1 = (-b + Math.Sqrt(result)) / (2 * a);
                double value2 = (-b - Math.Sqrt(result)) / (2 * a);
                //确保第一个点的x值比第二个点小
                if (value1 < value2)
                {
                    xArr.Add(value1);
                    xArr.Add(value2);
                }
                else
                {
                    xArr.Add(value2);
                    xArr.Add(value1);
                }
            } else if (result == 0)
            {
                xArr.Add(-b / (2 * a));
            }
            return xArr;
        }

        /// <summary>
        /// 在dxf中绘制线宽的圆弧，未将所有的情况考虑进去，请谨慎使用
        /// </summary>
        /// <param name="arc"></param>
        /// <param name="dxf"></param>
        /// <param name="lineWidth"></param>
        /// <param name="layercolor"></param>
        public static void arcWithWidth(Arc arc, DxfDocument dxf, double lineWidth,netDxf.Tables.Layer layercolor)
        {
            Vector2 startPoint = fun.Polar(fun.toTwo(arc.Center), arc.StartAngle * Math.PI / 180, arc.Radius);
            Vector2 endPoint = fun.Polar(fun.toTwo(arc.Center), arc.EndAngle * Math.PI / 180, arc.Radius);

            int sign = 1;
            double bulge = 0;
            double angle = arc.EndAngle - arc.StartAngle;
            if (startPoint.X < endPoint.X)
            {
                sign = -1;
            }

            if (angle < 0)
            {
                bulge =  -Math.Tan((2 * Math.PI - Math.Abs(angle) * Math.PI / 180 )/ 4);
            }else
            {
                bulge = Math.Tan(angle * Math.PI / 180 / 4);
            }

            LwPolyline poly = new LwPolyline();
            poly.Vertexes.Add(new LwPolylineVertex(startPoint));
            poly.Vertexes[0].Bulge = sign * bulge;
            poly.Vertexes.Add(new LwPolylineVertex(endPoint));
            fun.PolyFill(dxf, poly, lineWidth, layercolor);
        }

        /// <summary>
        /// 在dxf中绘制带线宽的圆
        /// </summary>
        /// <param name="circle"></param>
        /// <param name="dxf"></param>
        /// <param name="lineWidth"></param>
        /// <param name="layercolor"></param>
        public static void circleWithWidth(Circle circle, DxfDocument dxf, double lineWidth,
            netDxf.Tables.Layer layercolor)
        {
            Vector2 centerPoint = fun.toTwo(circle.Center);
            Vector2 leftPoint = fun.Polar(centerPoint, Math.PI, circle.Radius);
            Vector2 rightPoint = fun.Polar(centerPoint, 0, circle.Radius);
            
            LwPolyline poly1 = new LwPolyline();
            poly1.Vertexes.Add(new LwPolylineVertex(leftPoint));
            poly1.Vertexes[0].Bulge = Math.Tan(Math.PI / 4);
            poly1.Vertexes.Add(new LwPolylineVertex(rightPoint));
            fun.PolyFill(dxf, poly1, lineWidth, layercolor);
            
            LwPolyline poly2 = new LwPolyline();
            poly2.Vertexes.Add(new LwPolylineVertex(leftPoint));
            poly2.Vertexes[0].Bulge = -Math.Tan(Math.PI / 4);
            poly2.Vertexes.Add(new LwPolylineVertex(rightPoint));
            fun.PolyFill(dxf, poly2, lineWidth, layercolor);
        }

        /// <summary>
        /// 绘制线宽为lineWidth，颜色为layercolor的二维点数组的多段线
        /// </summary>
        /// <param name="line"></param>
        /// <param name="dxf"></param>
        /// <param name="lineWidth"></param>
        /// <param name="layercolor"></param>
        public static void drawLineWithWidth(Vector2[] line, DxfDocument dxf, double lineWidth,
            netDxf.Tables.Layer layercolor)
        {
            LwPolyline poly = new LwPolyline();
            for (int i = 0; i < line.Length; i++)
            {
                poly.Vertexes.Add(new LwPolylineVertex(line[i]));
            }
            fun.drawBLine(dxf, Pus.GetV2ArrayFromLwPolyline(poly), lineWidth, layercolor);
        }

        /// <summary>
        /// 二维数组所组成的多段线，关于X轴对称后所形成的多段线
        /// </summary>
        /// <param name="line"></param>
        /// <param name="dxf"></param>
        /// <param name="lineWidth"></param>
        /// <param name="layercolor"></param>
        public static void drawRotateXLineWithWidth(Vector2[] line, DxfDocument dxf, double lineWidth,
            netDxf.Tables.Layer layercolor)
        {
            LwPolyline poly = new LwPolyline();
            for (int i = 0; i < line.Length; i++)
            {
                poly.Vertexes.Add(new LwPolylineVertex(new Vector2(line[i].X,-line[i].Y)));
            }
            fun.drawBLine(dxf, Pus.GetV2ArrayFromLwPolyline(poly), lineWidth, layercolor);
        }
        
        /// <summary>
        /// 二维数组所组成的多段线，关于Y轴对称后所形成的多段线
        /// </summary>
        /// <param name="line"></param>
        /// <param name="dxf"></param>
        /// <param name="lineWidth"></param>
        /// <param name="layercolor"></param>
        public static void drawRotateYLineWithWidth(Vector2[] line, DxfDocument dxf, double lineWidth,
            netDxf.Tables.Layer layercolor)
        {
            LwPolyline poly = new LwPolyline();
            for (int i = 0; i < line.Length; i++)
            {
                poly.Vertexes.Add(new LwPolylineVertex(new Vector2(-line[i].X,line[i].Y)));
            }
            fun.drawBLine(dxf, Pus.GetV2ArrayFromLwPolyline(poly), lineWidth, layercolor);
        }

        /// <summary>
        /// GB/Z 29014.406 图9 曲线
        /// 方程有问题
        /// </summary>
        /// <param name="Dm"></param>
        /// <param name="e"></param>
        public static void specialCurve(DxfDocument dxf,double Dm, double e,netDxf.Tables.Layer layercolor)
        {
            double x = 0;
            double y = 0;
            double ang = 0;
            LwPolyline poly = new LwPolyline();
            for (int g = 0; g < 360; g += 20)
            {
                ang = g * Math.PI / 180;
                //ang值有问题
                x = Dm / (2 * Math.Cos(ang)) - 2 * e * Math.Cos(2 * ang) + e * Math.Cos(4 * ang);
                y = Dm / (2 * Math.Sin(ang)) + 2 * e * Math.Sin(2 * ang) + e * Math.Sin(4 * ang);
                Console.WriteLine("x={0},y={1}", x, y);
                poly.Vertexes.Add(new LwPolylineVertex(new Vector2(x, y)));
            }
            fun.PolyFill(dxf, poly, 0.2, layercolor);
        }

        /// <summary>
        /// 获得点point关于X轴或Y轴对称后的点
        /// </summary>
        /// <param name="point"></param>
        /// <param name="axis"></param>
        /// <returns></returns>
        public static Vector2 pointSymmetryOfAxis(Vector2 point, String axis)
        {
            if (axis.Equals("x") || axis.Equals("X"))
            {
                return new Vector2(point.X, -point.Y);
            }

            if (axis.Equals("y") || axis.Equals("Y"))
            {
                return new Vector2(-point.X, point.Y);
            }

            Console.WriteLine("输入有误,返回输入点");
            return point;
        }

                
        /// <summary>
        /// 获得点point关于经过p1,p2的直线对称的点
        /// </summary>
        /// <param name="point"></param>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        public static Vector2 pointSymmetryOfAxis(Vector2 point, Vector2 p1, Vector2 p2)
        {
            if (p1.X == p2.X && p1.Y == p2.Y)
            {
                Console.WriteLine("请输入两个不同位置的点");
                return point;
            }

            if (p1.X == p2.X)
            {
                return new Vector2(2 * p1.X - point.X, point.Y);
            }

            if (p1.Y == p2.Y)
            {
                return new Vector2(point.X, 2 * p1.Y - point.Y);
            }
            
            double[] kb = binaryEquationGetKB(p1, p2);
            double k = kb[0];

            double x = (k * p1.X + point.X / k + point.Y - p1.Y) / (1 / k + k);
            double y = (point.X - x) / k + point.Y;
            return new Vector2(2 * x - point.X, 2 * y - point.Y);
        }

        /// <summary>
        /// newOffset是关于两个点中最高的那个点的偏移
        /// </summary>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <param name="offset"></param>
        /// <param name="rotation"></param>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static LinearDimension LinearDimension(Vector2 point1, Vector2 point2, double offset,double rotation, DimensionStyle ds)
        {
            double newOffset = offset + Math.Abs(point1.X - point2.X) * Math.Sin(rotation * Math.PI / 180) / 2 +
                               Math.Abs(point1.Y - point2.Y) * Math.Cos(rotation * Math.PI / 180) / 2;
            return new LinearDimension(new Line(point1, point2), newOffset, rotation, ds);
        }
    }
}